home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Extravaganza - Disc 4
/
Shareware Extravaganza - Over 25,000 Programs (The Ultimate Shareware Company)(Disc 4 of 4)(1993).iso
/
cad
/
acdchord.zip
/
ACDCHORD.ASM
next >
Wrap
Assembly Source File
|
1990-07-14
|
26KB
|
1,033 lines
TITLE ACDCHORD.COM, an ADI driver to make AutoCAD use chords
PAGE ,132
;Written by Jon Fleming 6/2/90
; 144 Nagog Hill Road
; Acton, MA 01720
; BIXname: jfleming
;Released into the public domain.
;To create ACDCHORD.COM:
; MASM ACDCHORD;
; LINK ACDCHORD;
; EXE2BIN ACDCHORD.EXE ACDCHORD.COM
;This version was assembled with Microsoft MASM 5.1.
;If you have DOS 3.3 and do not have the technical reference, you probably
;don't have EXE2BIN. There are public domain programs that do the same thing
;(such as EXE2COM), available on many bulletin board systems.
;****************** EQUATES *********************
;general purpose
false equ 0
true equ 1
stdout equ 1 ;standard output device handle
tab equ 9
lf equ 0ah
form_feed equ 0ch
cr equ 0dh
esc_char equ 1bh
space equ 20h
;ACDCHORD equates
default_interrupt equ 79h ;default interrupt for us
; to communicate with
; AutoCAD
default_multiplier equ 24d ;default multiplier for all
;mouse motions
;AutoCAD codes
init_driver_code equ 1 ;codes for what AutoCAD
terminate_driver_code equ 2 ; wants
sense_state_code equ 3
interface_level equ 1 ;identifies driver interface
; version
;mouse codes
mouse_driver_installed equ 0FFFFh
read_pos_and_buttons equ 3
read_counters_function equ 0Bh
;********************** END EQUATES **************
stack segment stack ;just so the linker doesn't issue a
; warning.
stack ends ;DON'T put anything in this segment!
;collect all the segments in one group so we can turn this into a COM program
program group main_code,resident_data,transient_code,transient_data
assume cs:program,ds:program,es:program,ss:program
main_code segment
;************************** RESIDENT DATA *******************************
resident_data segment byte ;this segment will FOLLOW the
; resident code and contains all the
; data that will remain resident
; after terminate and stay resident
;call
; Translate table for a three button mouse, to translate single buttons
; and chords into AutoCAD button numbers
button_translate_table db 1 ;right button = button 1
db 4 ;left+right buttons = button 4
db 0 ;middle button = button 0
db 2 ;left+middle buttons = button 2
db 3 ;middle+right buttons = button 3
db 5 ;left+middle+right buttons = button 5
motion_scale_factor dw default_multiplier ;factor by which to
; multiply mouse motions
save_button_status db 0 ;space for saving button status until
; all buttons are released
x_coord dw 0 ;space for saving mouse position
y_coord dw 0
end_resident_data label byte ;used for getting resident size
resident_data ends
;************************ TRANSIENT DATA *****************************
transient_code segment byte ;the transient code will FOLLOW the
; resident data
transient_data segment byte ;the transient data will FOLLOW the
; transient code
installed_message db cr,lf,'AutoCAD/Chord mouse'
db ' driver installed, using interrupt '
int_num_ascii_1 dw ?
db ' (hexadecimal),',cr,lf,'occupying '
db 2 dup (space)
end_decimal_ascii_0 db space
db ' (decimal) bytes; mouse motions '
db 'multiplied by '
end_decimal_ascii_1 db space
db '.',cr,lf,'$'
not_installed_msg db cr,lf,'AutoCAD/Chord mouse'
db ' driver *NOT* installed '
db 'on interrupt '
int_num_ascii_3 dw ?
db ' (hexadecimal),',cr,lf
db 'operation aborted.',cr,lf,'$'
already_installed_msg db cr,lf,'AutoCAD/Chord mouse driver '
db 'already installed on interrupt '
int_num_ascii_4 dw ?
db ' (hexadecimal).',cr,lf,'$'
new_multiplier_msg db 'Multiplier set to '
end_decimal_ascii_2 db space
db '.',cr,lf,'$'
cmd_error_message db cr,lf,'AutoCAD/Chord mouse driver: '
db 'cannot decode command line.',cr,lf
db 'Valid command line items are:',cr,lf,lf
db '/Inn Use interrupt nn (hexadecimal).'
db cr,lf
db ' (nn MUST be two digits).',cr,lf
db ' The default interrupt number is '
int_num_ascii_0 dw ?
db '.',cr,lf,lf
db '/Mxx Multiply all mouse motions by xx '
db '(decimal).',cr,lf
db ' (xx may be one or more digits).'
db cr,lf
db ' The default multiplier is '
end_decimal_ascii_4 db space
db '.',cr,lf,lf,'The /M switch can be used after '
db 'installation to change the multiplier.'
db cr,lf,lf
db 'If ACDCHORD is already installed using '
db 'other than the default interrupt',cr,lf
db 'AND the multiplier is to be changed, the /I'
db ' switch MUST be included',cr,lf
db 'and MUST specify the same interrupt used'
db ' when ACDCHORD was installed.',cr,lf,lf,'$'
env_error_message db cr,lf,'error releasing environment space, '
db 'aborting.',cr,lf,'$'
interrupt_err_message db cr,lf,'Interrupt '
int_num_ascii_2 dw ?
db ' (hexadecimal) is in use already, '
db 'installation aborted.',cr,lf,'$'
bad_int_err_message db cr,lf,'Error, invalid hexadecimal interrupt'
db ' number.',cr,lf,'$'
bad_multiplier_err_msg db cr,lf,'Error, invalid number following'
db ' multiplier switch.',cr,lf,'$'
not_enough_room_msg db cr,lf,'Not enough memory available to'
db 'install driver, aborting',cr,lf,'$'
our_interrupt db default_interrupt
multiplier_update db false ;flag for whether we should update
; the multiplier in a resident copy
iret_instruction label byte
iret ;something to compare against to see
; if a byte is an interrupt return
transient_data ends
;************************* TRANSIENT CODE ********************
assume cs:program,ds:program,es:program,ss:program
start_transient_code:
mov dl,default_interrupt
call byte_to_hex_ascii ;convert default interrupt
xchg ah,al ; (swap to set up for word store)
mov int_num_ascii_0,ax ; to ASCII and store it where
mov int_num_ascii_1,ax ; we may need it later
mov int_num_ascii_2,ax
mov int_num_ascii_3,ax
mov int_num_ascii_4,ax
mov dx,motion_scale_factor ;convert the motion scale factor
mov di,offset program:end_decimal_ascii_1 ; to ASCII and store
call word_to_decimal_ascii ; it where we may
mov di,offset program:end_decimal_ascii_2 ; need it later
call word_to_decimal_ascii
mov di,offset program:end_decimal_ascii_4
call word_to_decimal_ascii
figure_out_what_to_do:
call scan_cmd_tail ;see if anything on command tail
jc try_to_install ;reached end of command tail
cmp al,'I'
je user_specified_interrupt
cmp al,'M'
je user_specified_multiplier
mov al,3 ;undecodable switch exit code
jmp error_exit
user_specified_interrupt:
lodsw ;get interrupt number
mov int_num_ascii_1,ax ;save into messages
mov int_num_ascii_2,ax
mov int_num_ascii_3,ax
mov int_num_ascii_4,ax
xchg ah,al ;set up for conversion
call hex_ascii_to_byte ;convert it to binary
jc user_specified_interrupt_error
mov our_interrupt,al ;and save it
jmp figure_out_what_to_do
user_specified_interrupt_error:
mov dx,offset program:bad_int_err_message
mov ah,9
int 21h
mov al,1 ;bad interrupt exit code
jmp error_exit
user_specified_multiplier:
call decimal_ascii_to_word ;convert to binary
cmp dx,0 ;check that it's OK
je user_specified_multiplier_error
mov motion_scale_factor,dx ;store in current copy of routine
mov end_decimal_ascii_1 - 1,space ;in case the new one is one
mov end_decimal_ascii_2 - 1,space ;digit and the old one was
; two digits
mov di,offset program:end_decimal_ascii_1 ;store the motion
call word_to_decimal_ascii ; scale factor in
mov di,offset program:end_decimal_ascii_2 ; the messages
call word_to_decimal_ascii
mov multiplier_update,true ;set flag for action later
jmp figure_out_what_to_do
user_specified_multiplier_error:
mov dx,offset program:bad_multiplier_err_msg
mov ah,9
int 21h
mov al,2 ;bad multiplier exit code
jmp error_exit
try_to_install:
mov al,our_interrupt
call check_interrupt ;see if the interrupt is free
cmp al,0
je ok_to_install ;nobody's there already
cmp al,1
je already_installed ;we're there already
;someone else is there
mov dx,offset program:interrupt_err_message
jmp short installation_error
already_installed:
mov dx,offset program:already_installed_msg
mov ah,9
int 21h ;write installation message
cmp multiplier_update,false
je already_installed_exit
;we need to update the
; multiplier in the resident copy
mov al,our_interrupt ;get the location of the resident
mov ah,35h ; copy
int 21h
assume es:nothing
mov ax,motion_scale_factor ;store the new multiplier in the
mov bx,offset program:motion_scale_factor ; resident copy
mov es:[bx],ax
mov ax,cs
mov es,ax
assume es:program
mov dx,offset program:new_multiplier_msg
mov ah,9
int 21h ;tell user we changed multiplier
already_installed_exit:
mov ax,4c00h
int 21h ;terminate, return code 0
ok_to_install:
mov ah,49h
mov bx,env_segment
mov es,bx
assume es:nothing
int 21h ;release our environment block
mov ax,cs
mov es,ax ;reestablish ES
assume es:program
jnc check_size
mov dx,offset program:env_error_message
jmp short installation_error
check_size:
mov dx,offset program:resident_data
add dx,15
mov cl,4
shr dx,cl ;dx = length of resident portion in
; paragraphs
push dx ;save for later
shl dx,cl ;convert back to bytes
mov di,offset program:end_decimal_ascii_0
call word_to_decimal_ascii ;let the user know how much room
; we're using
cmp dx,sp ;is there enough room for us?
jbe grab_the_interrupt
mov dx,offset program:not_enough_room_msg
mov ah,9
int 21h
mov al,4 ;insufficient room exit code
jmp short error_exit
grab_the_interrupt:
mov ah,25h
mov al,our_interrupt
mov dx,offset program:interrupt_handler
int 21h ;grab the interrupt
mov dx,offset program:installed_message
mov ah,9
int 21h ;write installation message
pop dx ;length of resident portion, paras
mov ax,3100h
int 21h ;terminate and stay resident
installation_error:
mov ah,9
int 21h ;describe error
mov dx,offset program:not_installed_msg
mov ah,9
int 21h ;tell user we didn't install
mov al,5 ;other installation error code
error_exit:
push ax ;save error code
mov dx,offset program:cmd_error_message
mov ah,9
int 21h ;show help
pop ax
mov ah,4ch
int 21h ;terminate with return code nonzero
;*************************** TRANSIENT SUPPORT ROUTINES **************
word_to_decimal_ascii proc near
;convert a 16 bit binary number in DX to its decimal ASCII equivalent, and
;store the result in the area pointed to by ES:DI. STORING IS BACKWARDS so
;ES:DI should point to the _END_ of the area where storage is desired.
push ax
push cx
push dx
pushf
std ;reverse moves
mov cx,10 ;divisor
word_to_decimal_ascii_loop:
mov ax,dx ;current binary value
xor dx,dx
div cx
xchg ax,dx ;quotient to AX
add al,30h ;next digit to ASCII
stosb ;store it
or dx,dx ;all done?
jnz word_to_decimal_ascii_loop
popf
pop dx
pop cx
pop ax
ret
word_to_decimal_ascii endp
byte_to_hex_ascii proc near
;converts an 8 bit number in DL to an ASCII hex representation in AX
push cx
mov cx,4
xor ah,ah
mov al,dl
shr ax,cl ;isolate upper four bits
lahf ;make sure auxiliary carry wasn't set
and ah,11101110b ; by "shr" op, which happens on some
sahf ; CPUs in the iapx family
daa ;add 6 if 0Ah through 0Fh
add al,0f0h ;and set carry if 0Ah through 0Fh
adc al,40h ;like magic, it's ASCII!
xchg ah,al ;save MSD in AH
mov al,dl
and al,0fh ;get lower four bits
daa ;add 6 if 0Ah through 0Fh
add al,0f0h ;and set carry if 0Ah through 0Fh
adc al,40h ;like magic, it's ASCII!
pop cx
ret
byte_to_hex_ascii endp
hex_ascii_to_byte proc near
;converts an ASCII string of two characters in AX to a binary number in AL.
;Returns carry set if error.
push dx
xor dx,dx
xchg ah,al
push ax
call hex_ascii_to_nibble
pop ax
jc end_hex_ascii_to_byte
push cx
mov cx,4
shl dx,cl
pop cx
xchg ah,al
call hex_ascii_to_nibble
jc end_hex_ascii_to_byte
mov ax,dx
end_hex_ascii_to_byte:
pop dx
ret
hex_ascii_to_nibble proc near
;Converts one hex digit in AL to binary and adds it to DX. Returns carry
;set if ASCII character in AL is not a valid hex digit. Accepts upper or
;lower case letters.
sub al,30h
jb hex_ascii_to_nibble_error
cmp al,9
jle add_it_to_dx
and al,5fh ;convert lower case
sub al,7
jb hex_ascii_to_nibble_error
cmp al,15
jg hex_ascii_to_nibble_error
add_it_to_dx:
cbw
add dx,ax
clc
ret
hex_ascii_to_nibble_error:
stc
ret
hex_ascii_to_nibble endp
hex_ascii_to_byte endp
current_cmd_tail_position dw 0 ;storage for use by
characters_left_in_cmd_tail db 0ffh ;scan_cmd_tail
scan_cmd_tail proc near
;procedure to get parameters off the command line. If no more parameters
;are present, returns carry set. If the next parameter is a switch (prefixed by
;"/" or "-"), the switch is returned in AL (converted to uppercase) and
;SI will point to the first character after the switch.
;Otherwise, AL will be zero; SI will point to the beginning of the
;parameter; and CX will contain the length of the parameter. In any case,
;SI, AH and CX are destroyed
push dx
clc ;assume more characters in tail
cmp characters_left_in_cmd_tail,0ffh ;assuming the command
jne not_first_call ; tail isn't ever really this long
mov al,cmd_tail_length
inc al ;include <return> in count
mov characters_left_in_cmd_tail,al
mov ax,offset program:cmd_tail ;initialize our variables
mov current_cmd_tail_position,ax
mov cl,cmd_tail_length
xor ch,ch
jcxz no_more_parameters
mov si,ax ;set up to capitalize the
mov di,ax ; entire command tail
capitalize_cmd_tail_loop:
lodsb
cmp al,'a'
jb end_capitalize_loop
cmp al,'z'
ja end_capitalize_loop
and al,0dfh ;convert to uppercase
end_capitalize_loop:
stosb
loop capitalize_cmd_tail_loop
not_first_call:
mov cl,characters_left_in_cmd_tail
xor ch,ch
jcxz no_more_parameters
mov si,current_cmd_tail_position
scan_tail_loop:
lodsb ;get next character
dec cx
cmp al,' ' ;see if it's whitespace
je scan_tail_loop
cmp al,tab
je scan_tail_loop
cmp al,cr ;check for end of tail
je no_more_parameters
cmp al,'/' ;found something, is it a switch?
je found_a_switch
cmp al,'-'
je found_a_switch
call scan_a_non_switch ;it's not a switch, scan it
inc cx ;correct character count
xor al,al ;flag that a non-switch was found
jmp short finished_scan_cmd_tail
found_a_switch:
lodsb ;get the switch
dec cx
push ax ;save it
call scan_a_non_switch ;get any trailing string
pop ax ;restore switch
inc si ;make SI point to trailing chars
jmp short finished_scan_cmd_tail
no_more_parameters:
stc
finished_scan_cmd_tail:
pop dx
ret
scan_a_non_switch proc near
;scans through a non-switch string or the string following a switch to
;find the end and the length.
push si ;found a non-switch, save beginning
push cx
loop_over_nonswitch_chars:
lodsb ;get next character
dec cx
cmp al,' ' ;see if it's whitespace
je found_end_of_nonswitch
cmp al,tab
je found_end_of_nonswitch
cmp al,'-' ;or maybe it's the beginning of
je found_end_of_nonswitch ;another switch
cmp al,'/'
je found_end_of_nonswitch
cmp al,cr ;check for end of tail
jne loop_over_nonswitch_chars
found_end_of_nonswitch:
dec si
mov current_cmd_tail_position,si ;save our state for next call
inc cl
mov characters_left_in_cmd_tail,cl
mov dx,cx ;get character count
pop cx
sub cx,dx
pop si ;get pointer to beginning of string
dec si
ret
scan_a_non_switch endp
scan_cmd_tail endp
check_interrupt proc near
;procedure to determine the status of a particular interrupt. Called with
;al = interrupt number. Returns 0 in al if there is no interrupt handler
;installed, 1 in al if this program is installed, 2 in al if some other
;program is installed. In any case, dx will contain the segment to
;which the vector currently points and bx will contain the offset.
;AH is destroyed.
push es
push di
push si
push cx
mov ah,35h
int 21h ;get interrupt vector
assume es:nothing
mov cx,es
mov dx,cx ;save segment of vector in dx
or cx,bx ;is the vector 0000:0000?
jz no_handler_installed ;yup, nobody home
mov al,es:[bx] ;get the byte to which it points
cmp al,iret_instruction
je no_handler_installed ;if it's just an interrupt return
; the handler is a dummy
;OK, someone appears to be installed. Is it us?
mov di,bx
;if it's us, es:di now points to the
; beginning of the code
; in the resident version
mov si,bx
;and ds:si points to the same code
; in this version
mov cx,interrupt_handler_length ;check all the code
cld
repe cmpsb ;are the two versions equal?
jcxz we_are_installed ;yup, it's gotta be us
mov al,2 ;somebody else is there, signature
jmp short end_check_interrupt ; didn't match
no_handler_installed:
xor al,al
jmp short end_check_interrupt
we_are_installed:
mov al,1 ;signature matched, we're installed
end_check_interrupt:
pop cx
pop si
pop di
pop es
assume es:program
ret
check_interrupt endp
decimal_ascii_to_word proc near
;converts the ASCII string pointed to by SI to a binary number. The first
;non-digit terminates the conversion. The binary number is returned
;in DX. Clears the direction flag. Returns SI pointing at the first
;non-digit character.
cld
push cx
push ax
xor dx,dx ;initialize DX
dec_ascii_loop:
lodsb ;get next digit
sub al,30h ;convert to number
jl dec_ascii_done ;terminate if too small
cmp al,9
jg dec_ascii_done ;terminate if too large
push ax ;save digit
mov ax,dx
mov cx,10
mul cx ;multiply curent number by 10
mov dx,ax ;put it back in DX
pop ax ;get digit back
add dx,ax ;add it to the current number
jmp dec_ascii_loop ;on to the next digit
dec_ascii_done:
dec si ;point SI at character that stopped us
pop ax
pop cx
ret
decimal_ascii_to_word endp
transient_code ends
;************************ RESIDENT INTERRUPT HANDLER CODE ***************
org 2ch
env_segment dw ? ;segment address of our environment
org 80h
cmd_tail_length db ? ;length of our command line tail
cmd_tail db ? ;contents of our command line tail
;Now we can actually start the main (resident) code
org 100h
assume cs:program,ds:program,es:program,ss:program
start:
jmp start_transient_code ;enter here only on initial
;(installation) call
interrupt_handler: ;entry point for interrupt
; handling routine
assume cs:program,ds:nothing,es:nothing,ss:nothing
sti ;resume the maddening buzz of
; interrupts
;we'll assume the caller has a big
; enough stack, since we don't use
; much
push ds ;we'll need to restore DS later
push ax ;we may need to restore AX later
; in case of a TERMINATE
push dx
push bx
push cx
push cs ;establish proper data segment
pop ds
assume ds:program
;select proper section of code to
;execute
dec ax
dec ax
jz terminate ;AX was equal to 2
js initialize ;AX was equal to 1 (or less)
;AX was equal to 3 (or more)
;********************** SECTION TO SENSE THE MOUSE STATE **********
sense_state:
mov ax,read_pos_and_buttons
int 33h ;ask the mouse what buttons are
; pressed
or bx,bx
jz no_buttons_pressed
or save_button_status,bl ;some button is pressed, save all
; button presses until they're all
; released. We'll ignore mouse
; motions until all buttons are
; released
pop cx ;restore CX, BX
pop bx
xor ax,ax ;return "nothing"
return_with_dx_popped:
pop dx ;restore DX
inc sp ;discard pushed AX
inc sp
pop ds ;restore DS
assume ds:nothing
iret
assume ds:program
no_buttons_pressed:
mov al,save_button_status ;no button is pressed; were any
or al,al ; buttons pressed previously?
jnz check_for_pick ;yup
;no buttons are or have been pressed
call get_position ;update current mouse position
mov ax,2 ;return "tracking"
jmp short return_coords
check_for_pick: ;at least one button has been
; pressed. check for special "pick"
dec al ; button
jnz return_button_and_coords
;left (pick) button was pressed
mov save_button_status,al ;reset button status to zero
;don't update coordinates so what
; counts is where the cursor was
; when the user PRESSED the pick
; button
mov ax,3 ;return "picked point"
return_coords:
add sp,4 ;discard pushed CX, BX
mov bx,x_coord
mov cx,y_coord
jmp return_with_dx_popped
return_button_and_coords: ;some button(s) other than just the
; left have been pressed
;translate to AutoCAD button number.
; note that save_button_status - 1
; is in AL, minimum value = 1,
; maximum value = 6
mov bx,offset program:button_translate_table-1
xlat
cbw
mov bx,ax ;BX = AutoCAD button number
mov save_button_status,ah ;reset button status
call get_position ;update current mouse position
mov cx,x_coord
mov dx,y_coord
mov ax,5 ;return "button and coordinates"
add sp,8 ;discard pushed CX, BX, DX, AX
pop ds ;restore DS
assume ds:nothing
iret
assume ds:program
;************************* SECTION TO TERMINATE *********************
terminate:
add sp,6 ;discard pushed DX, CX, BX
pop ax ;restore AX
pop ds ;restore DS
assume ds:nothing
iret
assume ds:program
;************************ SECTION TO INITIALIZE *********************
initialize:
cmp bx,interface_level
jne init_error_exit ;unknown interface level code
xor ax,ax ;check to see if mouse driver is
int 33h ; present (and zero motion counters)
cmp ax,mouse_driver_installed
jz how_many_buttons
;no mouse driver installed
init_error_exit:
xor ax,ax ;failed init code
pop cx ;restore CX and BX
pop bx
jmp short init_exit
how_many_buttons:
cmp bx,3 ;three button mouse?
jz init_ok ;yup
mov button_translate_table,0 ;nope, two buttons; need to
mov button_translate_table+1,1 ; change translate table so
; right button is button 0
; and left+right buttons is
; button 1
init_ok:
xor ax,ax ;initialize coordinates and
mov save_button_status,al ; button status
mov x_coord,ax
mov y_coord,ax
;set up return values
xor bx,bx ;relative pointing device
xor cx,cx ;continuous samples
inc ax ;init OK code = 1
pop dx ;discard pushed CX, BX
pop dx
init_exit:
pop dx ;restore DX
inc sp ;discard pushed AX
inc sp
pop ds
assume ds:nothing
iret
assume ds:program
;*************************** RESIDENT SUPPORT ROUTINES **************
get_position proc near
;procedure to get the increment of mouse motions since the last call
;and update the "absolute" X and Y coordinates. Destroys AX, BX, CX, DX.
mov ax,read_counters_function
int 33h ;ask the mouse where it's moved to
mov ax,dx ;y motion in mickeys
neg ax ;AutoCAD & mouse use opposite signs
imul motion_scale_factor ;scale it up (32 bit result)
add ax,y_coord ;add current position (32 bit
adc dx,0 ; addition, but we know the top
; 16 bits of current position are 0)
js set_y_to_zero ;if result negative, clip to min
jnz set_y_to_max ;if DX positive but nonzero, clip to
; max
cmp ax,20480d
jna save_y ;if AX isn't too big, just save
set_y_to_max:
mov ax,20480d ;maximum value of y coordinate
jmp short save_y
set_y_to_zero:
xor ax,ax ;0 = minimum value of y coordinate
save_y:
mov y_coord,ax
mov ax,cx ;x motion in mickeys
imul motion_scale_factor ;scale it up (32 bit result)
add ax,x_coord ;add current position (32 bit
adc dx,0 ; addition, but we know the top
; 16 bits of current position are 0)
js set_x_to_zero ;if result negative, clip to min
jnz set_x_to_max ;if DX positive but nonzero, clip to
; max
cmp ax,20480d
jna save_x ;if AX isn't too big, just save it
set_x_to_max:
mov ax,20480d ;maximum value of x coordinate
jmp short save_x
set_x_to_zero:
xor ax,ax ;0 = minimum value of x coordinate
save_x:
mov x_coord,ax ;save x coordinate
ret
interrupt_handler_length equ $ - interrupt_handler
get_position endp
main_code ends
end start